<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
    />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Point to Point Constraint</title>
    <link rel="stylesheet" href="/css/examples.css?ver=1.0.0" />
    <script src="/js/examples.js?ver=1.1.1"></script>
    <script src="/lib/three.min.js"></script>
    <script src="/lib/enable3d/enable3d.ammoPhysics.0.22.0.min.js"></script>
    <!-- <script src="/lib/OrbitControls.js"></script> -->
  </head>

  <body>
    <div id="info-text">Use the mouse to move the object</div>
    <script>
      const { AmmoPhysics, PhysicsLoader } = ENABLE3D

      const MainScene = () => {
        // scene
        const scene = new THREE.Scene()
        scene.background = new THREE.Color(0xf0f0f0)

        // camera
        const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000)
        camera.position.set(-10, 6, 6)
        camera.lookAt(2, 0, 0)

        // renderer
        const renderer = new THREE.WebGLRenderer()
        renderer.setSize(window.innerWidth, window.innerHeight)
        document.body.appendChild(renderer.domElement)

        // dpr
        const DPR = window.devicePixelRatio
        renderer.setPixelRatio(Math.min(2, DPR))

        // orbit controls
        // const controls = new THREE.OrbitControls(camera, renderer.domElement)

        // light
        scene.add(new THREE.HemisphereLight(0xffffbb, 0x080820, 1))
        scene.add(new THREE.AmbientLight(0x666666))
        const light = new THREE.DirectionalLight(0xdfebff, 1)
        light.position.set(50, 200, 100)
        light.position.multiplyScalar(1.3)

        // physics
        const physics = new AmmoPhysics(scene, { gravity: { x: 0, y: 0, z: 0 } })
        physics.debug.enable()

        // factory
        const { factory } = physics

        const back = physics.add.box({ x: 0, width: 5, depth: 0.2 })

        const front = physics.add.box({ x: 2.85, z: 3.1, width: 0.3, depth: 0.2, collisionFlags: 0, mass: 0 })
        const ball = physics.add.sphere({ x: -2.6, radius: 0.05, collisionFlags: 0, mass: 0 })

        const pole1 = factory.add.cylinder({ x: 2.4, y: 0.4, z: 1.5, height: 3, radiusBottom: 0.1, radiusTop: 0.1 })
        pole1.rotateX(Math.PI / 2)
        physics.add.existing(pole1)
        pole1.body.setCollisionFlags(4)
        pole1.body.setAngularFactor(1, 1, 0)

        const pole2 = factory.add.cylinder({ x: 2.4, y: -0.4, z: 1.5, height: 3, radiusBottom: 0.1, radiusTop: 0.1 })
        pole2.rotateX(Math.PI / 2)
        physics.add.existing(pole2)
        pole2.body.setCollisionFlags(4)
        pole2.body.setAngularFactor(1, 1, 0)

        physics.add.constraints.pointToPoint(back.body, pole1.body, {
          pivotA: { x: 2.5, y: 0.5, z: 0 },
          pivotB: { x: 0, y: -1.6, z: 0 }
        })

        physics.add.constraints.pointToPoint(back.body, pole2.body, {
          pivotA: { x: 2.5, y: -0.5, z: 0 },
          pivotB: { x: 0, y: -1.6, z: 0 }
        })

        physics.add.constraints.pointToPoint(front.body, pole1.body, {
          pivotA: { x: 0, y: 0.5, z: 0 },
          pivotB: { x: 0, y: 1.6, z: 0 }
        })

        physics.add.constraints.pointToPoint(front.body, pole2.body, {
          pivotA: { x: 0, y: -0.5, z: 0 },
          pivotB: { x: 0, y: 1.6, z: 0 }
        })

        physics.add.constraints.pointToPoint(back.body, ball.body, {
          pivotA: { x: -2.5, y: 0, z: 0 },
          pivotB: { x: 0.1, y: 0, z: 0 }
        })

        let mouseDown = false
        let mouseMove = false
        let position = { x: 0, y: 0 }
        let movement = { x: 0, y: 0 }

        const down = (x, y) => {
          position = { x, y }
          movement = { x, y }
          mouseDown = true
        }

        const up = () => {
          position = { x: 0, y: 0 }
          movement = { x: 0, y: 0 }
          mouseDown = false
          mouseMove = false
        }

        const move = (x, y) => {
          if (mouseDown) {
            mouseMove = true
            movement = { x: x - position.x, y: y - position.y }
            position = { x: x, y: y }
          }
        }

        window.addEventListener('mousedown', e => down(e.clientX, e.clientY))
        window.addEventListener('mouseup', up)
        window.addEventListener('mousemove', e => move(e.clientX, e.clientY))

        window.addEventListener('touchstart', e => down(e.touches[0].clientX, e.touches[0].clientY))
        window.addEventListener('touchend', up)
        window.addEventListener('touchmove', e => move(e.touches[0].clientX, e.touches[0].clientY))

        // clock
        const clock = new THREE.Clock()

        // loop
        const animate = () => {
          physics.update(clock.getDelta() * 1000)
          physics.updateDebugger()

          back.body.setAngularVelocity(0, 0, 0)

          if (mouseMove) {
            const speed = -0.5
            back.body.setAngularVelocityZ(movement.y * speed)
            back.body.setVelocityZ(-0.5)
            mouseMove = false
          }

          renderer.render(scene, camera)
          requestAnimationFrame(animate)
        }
        requestAnimationFrame(animate)
      }

      PhysicsLoader('/lib/ammo/kripken', () => MainScene())

      console.log(`three.js version "${THREE.REVISION}"`)
    </script>
  </body>
</html>
